package pnu.ssm.view;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.Iterator;
import java.util.Scanner;

import pnu.ssm.controller.factory.CommandFactory;
import pnu.ssm.controller.factory.StuffFactory;
import pnu.ssm.controller.manager.BlockManager;
import pnu.ssm.controller.manager.FactoryManager;
import pnu.ssm.controller.manager.JobManager;
import pnu.ssm.controller.manager.TileManager;
import pnu.ssm.controller.manager.TransporterManager;
import pnu.ssm.ga.Individual;
import pnu.ssm.model.GPosition;
import pnu.ssm.model.command.Command;
import pnu.ssm.model.job.Job;
import pnu.ssm.model.stuff.Block;
import pnu.ssm.model.stuff.Factory;
import pnu.ssm.model.stuff.Stuff;
import pnu.ssm.model.stuff.Transporter;
import pnu.ssm.model.tile.Tile;
import pnu.ssm.model.tile.TileEnum;

public class Dispatcher {
	public static boolean Debug = false;
	
	private final String FILE_MAP_INFO = "mapInfo.txt";
	private final String FILE_JOB_LIST = "jobList.txt";
	private final String FILE_OUTPUT = "output.txt";

	private static final Scanner scan = new Scanner(System.in);

	private TransporterManager transporterMgr;
	private FactoryManager factoryMgr;
	private BlockManager blockMgr;
	private JobManager jobMgr;
	private TileManager tileMgr;

	private FileInputStream fis;
	private BufferedReader br;

	private FileOutputStream fos;
	private BufferedWriter bw;

	private final String FORMAT_TYPE = "%10s ";
	
	public Dispatcher() {
		factoryMgr = FactoryManager.getInstance();
		transporterMgr = TransporterManager.getInstance();
		blockMgr = BlockManager.getInstance();
		jobMgr = JobManager.getInstance();
		tileMgr = TileManager.getInstance();
	}
	
	public void readFile(){
		readSituation();
		readJobList();
		Individual.setDefaultGeneLength(jobMgr.getSize());
		Individual.setMaximumGeneNumber(transporterMgr.getSize());
	}
	
	public void init(){
		factoryMgr.init();
		transporterMgr.init();
		blockMgr.init();
		jobMgr.init();
		tileMgr.init();
		readSituation();
		readJobList();
	}

	private void writeReport() {
		try {
			fos = new FileOutputStream(FILE_OUTPUT);
			bw = new BufferedWriter(new OutputStreamWriter(fos));
			bw.write("==================Report====================\n");
			Iterator<Transporter> it = transporterMgr.iterator();
			int totalEmptyDis = 0;
			int totalDistance = 0;
			while (it.hasNext()) {
				Transporter t = it.next();
				totalEmptyDis += t.getEmptyDis();
				totalDistance += t.getTotalDis();
				bw.write(t + " : Empty distance (" + t.getEmptyDis()+ "), Moved distance (" + t.getTotalDis() + ")\n");
			}
			bw.write("Total empty distance (" + totalEmptyDis+ "), Total moved distance (" + totalDistance + ")\n");
			bw.write("==================End====================\n");
			bw.flush();
			bw.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	private void readJobList() {
		try {
			fis = new FileInputStream(FILE_JOB_LIST);
			br = new BufferedReader(new InputStreamReader(fis));
			String tempStr = br.readLine();
			String[] strArr;
			int jobCnt = Integer.parseInt(tempStr);
			for (int i = 0; i < jobCnt; i++) {
				tempStr = br.readLine();
				strArr = tempStr.split(" ");
				String jobFactory = strArr[0];
				String jobCommnad = strArr[1];
				String jobBlock = strArr[2];
				Factory f = factoryMgr.getFactory(jobFactory);
				Command c = CommandFactory.create(jobCommnad);
				Block b = blockMgr.getBlock(jobBlock);
				Job newJob = new Job(f, c, b);
				jobMgr.addJob(newJob);
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private void readSituation() {
		try {
			fis = new FileInputStream(FILE_MAP_INFO);
			br = new BufferedReader(new InputStreamReader(fis));
			String tempStr = "";
			while ((tempStr = br.readLine()) != null) {
				if (tempStr.equals("MAP")) {
					readMap();
				} else if (tempStr.equals("FACTORY")) {
					readFactory();
				} else if (tempStr.equals("TRANSPORTER")) {
					readTransporter();
				} else if (tempStr.equals("BLOCK")) {
					readBlock();
				} else {
					continue;
				}
			};
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}

	private void readMap() throws IOException {
		String tempStr = "";
		String[] strArr;
		tempStr = br.readLine();
		int tileSize = Integer.parseInt(tempStr);

		tempStr = br.readLine();
		strArr = tempStr.split(" ");
		Tile[][] mapInfo = new Tile[Integer.parseInt(strArr[1])][Integer.parseInt(strArr[0])];

		for (int i = 0; i < mapInfo.length; i++) {
			int k = 0;
			tempStr = br.readLine();
			strArr = tempStr.split(" ");
			for (int j = 0; j < mapInfo[i].length; j++) {
				int tempTileNumber = Integer.parseInt(strArr[k++]);
				Stuff s = StuffFactory.create(TileEnum.values()[tempTileNumber], new GPosition(j, i));
				mapInfo[i][j] = new Tile(s);
			}
		}
		tileMgr.setMap(tileSize, mapInfo);
	}

	private void readFactory() throws IOException {
		String tempStr = "";
		String[] strArr;
		tempStr = br.readLine();
		int factoryCnt = Integer.parseInt(tempStr);

		for (int i = 0; i < factoryCnt; i++) {
			tempStr = br.readLine();
			strArr = tempStr.split(" ");
			String name = strArr[0];
			int y = Integer.parseInt(strArr[1]);
			int x = Integer.parseInt(strArr[2]);
			Factory f = new Factory(name, new GPosition(x, y));
			factoryMgr.addFactory(f);
			tileMgr.setStuffToTile(x, y, f);
		}
	}

	private void readTransporter() throws IOException {
		String tempStr = "";
		String[] strArr;
		tempStr = br.readLine();
		int transporterCnt = Integer.parseInt(tempStr);
		
		for (int i = 0; i < transporterCnt; i++) {
			tempStr = br.readLine();
			strArr = tempStr.split(" ");
			String name = strArr[0];
			int x = Integer.parseInt(strArr[1]);
			int y = Integer.parseInt(strArr[2]);
			int velocity = Integer.parseInt(strArr[3]);
			Transporter t = new Transporter(name, new GPosition(x, y),
					velocity, tileMgr.getMap());
			transporterMgr.addTransporter(t);
		}
	}

	private void readBlock() throws IOException {
		String tempStr = "";
		String[] strArr;
		tempStr = br.readLine();
		int blockNum = Integer.parseInt(tempStr);
		for (int i = 0; i < blockNum; i++) {
			tempStr = br.readLine();
			strArr = tempStr.split(" ");
			String name = strArr[0];
			int x = Integer.parseInt(strArr[1]);
			int y = Integer.parseInt(strArr[2]);
			int weight = Integer.parseInt(strArr[3]);

			Block b = new Block(name, new GPosition(x, y), weight);
			blockMgr.addBlock(b);
		}
	}

	public static void clearScreen() {
		for (int i = 0; i < 80; i++)
			System.out.println("");
	}

//	private void displayByWorking(Tile[][] map) {
//		System.out.println();
//		String[][] displayer = new String[tileMgr.getMapRow()][tileMgr
//				.getMapCol()];
//
//		for (int i = 0; i < map.length; i++) {
//			for (int j = 0; j < map[i].length; j++) {
//				displayer[i][j] = map[i][j].getStuff().getName();
//			}
//		}
//
//		Iterator<Block> bkTrans = blockMgr.iterator();
//		while (bkTrans.hasNext()) {
//			Block b = bkTrans.next();
//			int x = b.getPos().getX();
//			int y = b.getPos().getY();
//			displayer[y][x] = b.getName();
//		}
//
//		for (int i = 0; i < displayer.length; i++) {
//			for (int j = 0; j < displayer[i].length; j++) {
//				System.out.format(FORMAT_TYPE, displayer[i][j]);
//			}
//			System.out.println();
//		}
//		scan.nextLine();
//	}
}
